namespace Guia.Locator
{
    using System;
    using System.Windows.Automation;
    using Guia.Config;
    using Guia.Core;
    using Guia.Elements;
    using System.Diagnostics.Contracts;

    /// <summary>
    /// This class contains some helper functionalities to access the window.
    /// </summary>
    public class WindowHelper
    {
        /// <summary>
        /// Time to wait for a window.
        /// </summary>
        private static readonly int WindowFinderTimeout;

        /// <summary>
        /// The Configuration.
        /// </summary>
        private static readonly IConfig Configuration;

        /// <summary>
        /// Initializes static members of the <see cref="WindowHelper"/> class.
        /// </summary>
        static WindowHelper()
        {
            Configuration = AppConfigImpl.Instance;
            WindowFinderTimeout = Configuration.WindowTimeout;
        }
        
        /// <summary>
        /// Gets the window according the given conditions.
        /// </summary>
        /// <param name="searchCondition">The SearchCondition to find the window.</param>
        /// <param name="processId">The process-id of the window.</param>
        /// <returns>The desired window.</returns>
        /// <exception cref="ArgumentNullException">This exception is thrown if searchCondition is null.</exception>
        /// <exception cref="ElementNotFoundException"/>
        public static Window GetWindowBySearchCondition(SearchCondition searchCondition, int processId)
        {
            Contract.Requires<ArgumentNullException>(searchCondition != null);
            Window window = null;
            Action doAction = () =>
                                  {
                                      try
                                      {
                                          SearchCondition finalCondition =
                                              searchCondition.And(SearchCondition.ByProcessId(processId));
                                          finalCondition.Scope = TreeScope.Children;

                                          do
                                          {
                                              try
                                              {
                                                  window = UiElementFactory.GetUiElement<Window>(UiElement.RootElement, searchCondition);
                                              }
                                              catch (ElementNotFoundException)
                                              {
                                              }
                                          } 
                                          while (window == null);
                                      }
                                      catch
                                      {
                                          throw new ElementNotFoundException(
                                              "Could not find Window with the SearchCondition " +
                                              searchCondition.ToString());
                                      }
                                  };
            Action timeoutAction = () =>
                                       {
                                           throw new ElementNotFoundException("Could not find Window with the SearchCondition " + searchCondition.ToString());
                                       };
            Clock.Run(doAction, timeoutAction, WindowFinderTimeout);
            return window;
        }
    }
}